﻿/**
 * Peter
 * Created by: Peter Development Team
 *    http://peter.codeplex.com/
 * 
 * GNU General Public License version 2 (GPLv2)
 *    http://peter.codeplex.com/license
 *
 *  This code is provided on an AS IS basis, with no WARRANTIES,
 *  CONDITIONS or GUARANTEES of any kind.
 *
 **/

using System;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace Peter.Common.Code.Images
{
   /// <summary>
   /// Code image helpers.
   /// </summary>
   public class CodeImage
   {/*
      private const int ACCESSIBILITY_OVERLAYS_LENGTH = 5;
      private static BitmapImage s_NamespaceImage;
      private static readonly CodeImage s_ImageClass = new CodeImage ("Class", false);
      private static readonly CodeImage s_ImageStruct = new CodeImage ("Struct", false);
      private static readonly CodeImage s_ImageInterface = new CodeImage ("Interface", false);
      private static readonly CodeImage s_ImageDelegate = new CodeImage ("Delegate", false);
      private static readonly CodeImage s_ImageEnum = new CodeImage ("Enum", false);
      private static readonly CodeImage s_ImageStaticClass = new CodeImage ("StaticClass", false);
      private static readonly CodeImage s_ImageField = new CodeImage ("Field", true);
      private static readonly CodeImage s_ImageFieldReadOnly = new CodeImage ("FieldReadOnly", true);
      private static readonly CodeImage s_ImageLiteral = new CodeImage ("Literal", false);
      private static readonly CodeImage s_ImageEnumValue = new CodeImage ("EnumValue", false);
      private static readonly CodeImage s_ImageMethod = new CodeImage ("Method", true);
      private static readonly CodeImage s_ImageConstructor = new CodeImage ("Constructor", true);
      private static readonly CodeImage s_ImageVirtualMethod = new CodeImage ("VirtualMethod", true);
      private static readonly CodeImage s_ImageOperator = new CodeImage ("Operator", false);
      private static readonly CodeImage s_ImageExtensionMethod = new CodeImage ("ExtensionMethod", true);
      private static readonly CodeImage s_ImagePInvokeMethod = new CodeImage ("PInvokeMethod", true);
      private static readonly CodeImage s_ImageProperty = new CodeImage ("Property", true);
      private static readonly CodeImage s_ImageIndexer = new CodeImage ("Indexer", true);
      private static readonly CodeImage s_ImageEvent = new CodeImage ("Event", true);
      private static readonly BitmapImage s_OverlayStatic = LoadBitmap ("OverlayStatic");

      /// <summary>
      /// Gets the image for namespaces.
      /// </summary>
      public static ImageSource NamespaceImage
      {
         get { return s_NamespaceImage ?? (s_NamespaceImage = LoadBitmap ("NameSpace")); }
      }

      /// <summary>Gets the image used for non-static classes.</summary>
      public static CodeImage Class { get { return s_ImageClass; } }
      
      /// <summary>Gets the image used for structs.</summary>
      public static CodeImage Struct { get { return s_ImageStruct; } }
      
      /// <summary>Gets the image used for interfaces.</summary>
      public static CodeImage Interface { get { return s_ImageInterface; } }
      
      /// <summary>Gets the image used for delegates.</summary>
      public static CodeImage Delegate { get { return s_ImageDelegate; } }
      
      /// <summary>Gets the image used for enums.</summary>
      public static CodeImage Enum { get { return s_ImageEnum; } }
      
      /// <summary>Gets the image used for modules/static classes.</summary>
      public static CodeImage StaticClass { get { return s_ImageStaticClass; } }
      
      /// <summary>Gets the image used for non-static classes.</summary>
      public static CodeImage Field { get { return s_ImageField; } }
      
      /// <summary>Gets the image used for structs.</summary>
      public static CodeImage ReadOnlyField { get { return s_ImageFieldReadOnly; } }
      
      /// <summary>Gets the image used for constants.</summary>
      public static CodeImage Literal { get { return s_ImageLiteral; } }
      
      /// <summary>Gets the image used for enum values.</summary>
      public static CodeImage EnumValue { get { return s_ImageEnumValue; } }
      
      /// <summary>Gets the image used for methods.</summary>
      public static CodeImage Method { get { return s_ImageMethod; } }
      
      /// <summary>Gets the image used for constructos.</summary>
      public static CodeImage Constructor { get { return s_ImageConstructor; } }
      
      /// <summary>Gets the image used for virtual methods.</summary>
      public static CodeImage VirtualMethod { get { return s_ImageVirtualMethod; } }
      
      /// <summary>Gets the image used for operators.</summary>
      public static CodeImage Operator { get { return s_ImageOperator; } }
      
      /// <summary>Gets the image used for extension methods.</summary>
      public static CodeImage ExtensionMethod { get { return s_ImageExtensionMethod; } }
      
      /// <summary>Gets the image used for P/Invoke methods.</summary>
      public static CodeImage PInvokeMethod { get { return s_ImagePInvokeMethod; } }
      
      /// <summary>Gets the image used for properties.</summary>
      public static CodeImage Property { get { return s_ImageProperty; } }
      
      /// <summary>Gets the image used for indexers.</summary>
      public static CodeImage Indexer { get { return s_ImageIndexer; } }
      
      /// <summary>Gets the image used for events.</summary>
      public static CodeImage Event { get { return s_ImageEvent; } }

      /// <summary>
      /// Loads a code image bitmap.
      /// </summary>
      /// <param name="name">Name of image to load.</param>
      /// <returns>The requested image.</returns>
      private static BitmapImage LoadBitmap (string name)
      {
         var image = new BitmapImage (new Uri ("pack://application:,,,/Peter.Common;component/Code/Images/" + name + ".png"));
         image.Freeze ();
         return image;
      }
      
      /// <summary>
      /// Gets the CodeImage instance for the specified entity.
      /// Returns null when no image is available for the entity type.
      /// </summary>
      public static CodeImage GetCodeImage(IEntity entity)
      {
         if (entity == null)
            throw new ArgumentNullException("entity");
         switch (entity.SymbolKind) {
            case SymbolKind.TypeDefinition:
               return GetCodeImageForType(((ITypeDefinition)entity).Kind, entity.IsStatic);
            case SymbolKind.Field:
               var field = (IField)entity;
               if (field.IsConst)
               {
                  if (field.DeclaringTypeDefinition != null && field.DeclaringTypeDefinition.Kind == TypeKind.Enum)
                     return s_ImageEnumValue;
                  return s_ImageLiteral;
               }
               return field.IsReadOnly ? s_ImageFieldReadOnly : s_ImageField;
            case SymbolKind.Method:
               var method = (IMethod)entity;
               if (method.IsExtensionMethod)
                  return s_ImageExtensionMethod;
               return method.IsOverridable ? s_ImageVirtualMethod : s_ImageMethod;
            case SymbolKind.Property:
               return s_ImageProperty;
            case SymbolKind.Indexer:
               return s_ImageIndexer;
            case SymbolKind.Event:
               return s_ImageEvent;
            case SymbolKind.Operator:
            case SymbolKind.Destructor:
               return s_ImageOperator;
            case SymbolKind.Constructor:
               return s_ImageConstructor;
            default:
               return null;
         }
      }
   
      /// <summary>
      /// Gets the CodeImage instance for the specified entity.
      /// Returns null when no image is available for the entity type.
      /// </summary>
      public static CodeImage GetCodeImage(IUnresolvedEntity entity)
      {
         if (entity == null)
            throw new ArgumentNullException("entity");
         switch (entity.SymbolKind) {
                case SymbolKind.TypeDefinition:
               return GetCodeImageForType(((IUnresolvedTypeDefinition)entity).Kind, entity.IsStatic);
                case SymbolKind.Field:
               var field = (IUnresolvedField)entity;
               if (field.IsConst)
               {
                  if (field.DeclaringTypeDefinition != null && field.DeclaringTypeDefinition.Kind == TypeKind.Enum)
                     return s_ImageEnumValue;
                  return s_ImageLiteral;
               }
               return field.IsReadOnly ? s_ImageFieldReadOnly : s_ImageField;
                case SymbolKind.Method:
               var method = (IUnresolvedMethod)entity;
               return method.IsOverridable ? s_ImageVirtualMethod : s_ImageMethod;
                case SymbolKind.Property:
               return s_ImageProperty;
                case SymbolKind.Indexer:
               return s_ImageIndexer;
                case SymbolKind.Event:
               return s_ImageEvent;
                case SymbolKind.Operator:
                case SymbolKind.Destructor:
               return s_ImageOperator;
                case SymbolKind.Constructor:
               return s_ImageConstructor;
            default:
               return null;
         }
      }
      
      static CodeImage GetCodeImageForType(TypeKind typeKind, bool isStatic)
      {
         switch (typeKind) {
            case TypeKind.Interface:
               return s_ImageInterface;
            case TypeKind.Struct:
            case TypeKind.Void:
               return s_ImageStruct;
            case TypeKind.Delegate:
               return s_ImageDelegate;
            case TypeKind.Enum:
               return s_ImageEnum;
            case TypeKind.Class:
               return isStatic ? s_ImageStaticClass : s_ImageClass;
            case TypeKind.Module:
               return s_ImageStaticClass;
            default:
               return null;
         }
      }
      
      /// <summary>
      /// Gets the image for the specified entity.
      /// Returns null when no image is available for the entity type.
      /// </summary>
      public static ImageSource GetImage(IEntity entity)
      {
         var image = GetCodeImage(entity);
         return image != null ? image.GetImage(entity.Accessibility, entity.IsStatic) : null;
      }
      
      /// <summary>
      /// Gets the image for the specified entity.
      /// Returns null when no image is available for the entity type.
      /// </summary>
      public static ImageSource GetImage(IUnresolvedEntity entity)
      {
         var image = GetCodeImage(entity);
         return image != null ? image.GetImage(entity.Accessibility, entity.IsStatic) : null;
      }

      /// <summary>
      /// Gets the overlay image for the static modifier.
      /// </summary>
      public ImageSource StaticOverlay { get { return s_OverlayStatic; } }
      
      static readonly BitmapImage[] s_AccessibilityOverlays =
      {
         null,
         LoadBitmap("OverlayPrivate"),
         LoadBitmap("OverlayProtected"),
         LoadBitmap("OverlayInternal"),
         LoadBitmap("OverlayProtectedInternal")
      };
      
      /// <summary>
      /// Gets an overlay image for the specified accessibility.
      /// Returns null if no overlay exists (for example, public members don't use overlays).
      /// </summary>
      public static ImageSource GetAccessibilityOverlay(Accessibility accessibility)
      {
         return s_AccessibilityOverlays[GetAccessibilityOverlayIndex(accessibility)];
      }
      
      static int GetAccessibilityOverlayIndex(Accessibility accessibility)
      {
         switch (accessibility) {
            case Accessibility.Private:
               return 1;
            case Accessibility.Protected:
               return 2;
            case Accessibility.Internal:
               return 3;
            case Accessibility.ProtectedOrInternal:
            case Accessibility.ProtectedAndInternal:
               return 4;
            default:
               return 0;
         }
      }

      private readonly string m_ImageName;
      private readonly bool m_ShowStaticOverlay;
      
      private CodeImage(string imageName, bool showStaticOverlay)
      {
         this.m_ImageName = imageName;
         this.m_ShowStaticOverlay = showStaticOverlay;
      }

      private readonly ImageSource[] m_Images = new ImageSource[2 * ACCESSIBILITY_OVERLAYS_LENGTH];
      // 0..N-1  = base image + accessibility overlay
      // N..2N-1 = base image + static overlay + accessibility overlay
      
      /// <summary>
      /// Gets the image without any overlays.
      /// </summary>
      public ImageSource BaseImage {
         get {
            var image = m_Images[0];
            if (image == null) {
               image = LoadBitmap(m_ImageName);
               Thread.MemoryBarrier();
               m_Images[0] = image;
            }
            return image;
         }
      }
      
      /// <summary>
      /// Gets this image combined with the specified accessibility overlay.
      /// </summary>
      public ImageSource GetImage(Accessibility accessibility, bool isStatic = false)
      {
         int accessibilityIndex = GetAccessibilityOverlayIndex(accessibility);
         int index;
         if (isStatic && m_ShowStaticOverlay)
            index = s_AccessibilityOverlays.Length + accessibilityIndex;
         else
            index = accessibilityIndex;
         
         if (index == 0)
            return this.BaseImage;
         
         ImageSource image = m_Images[index];
         if (image == null) {
            var g = new DrawingGroup();
            var iconRect = new Rect(0, 0, 16, 16);
            g.Children.Add(new ImageDrawing(this.BaseImage, iconRect));
            
            if (s_AccessibilityOverlays[accessibilityIndex] != null)
               g.Children.Add(new ImageDrawing(s_AccessibilityOverlays[accessibilityIndex], iconRect));
            
            image = new DrawingImage(g);
            image.Freeze();
            Thread.MemoryBarrier();
            m_Images[index] = image;
         }
         return image;
      }
      
      /// <inheritdoc/>
      public override string ToString()
      {
         return "[CodeImage " + m_ImageName + "]";
      }*/
   }
}
